"""
性能监控集成接口

统一管理所有性能监控功能，包括：
- 查询优化器性能监控
- 数据聚合优化器性能监控  
- 分区策略管理器性能监控
- 批量操作优化器性能监控
- 系统整体性能监控
"""

import asyncio
import time
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Any, Union, Tuple
from dataclasses import dataclass, field
from enum import Enum
import json
import logging
from collections import defaultdict, deque
import statistics

from .config import config
from .cache import cache_manager
from .database import db_manager

logger = logging.getLogger(__name__)


class MetricType(Enum):
    """性能指标类型"""
    QUERY = "query"
    AGGREGATION = "aggregation"
    PARTITION = "partition"
    BATCH = "batch"
    CACHE = "cache"
    DATABASE = "database"
    SYSTEM = "system"


class AlertLevel(Enum):
    """告警级别"""
    INFO = "info"
    WARNING = "warning"
    ERROR = "error"
    CRITICAL = "critical"


@dataclass
class PerformanceMetric:
    """性能指标数据结构"""
    metric_type: MetricType
    name: str
    value: Union[int, float]
    unit: str
    timestamp: datetime = field(default_factory=datetime.now)
    tags: Dict[str, str] = field(default_factory=dict)
    metadata: Dict[str, Any] = field(default_factory=dict)


@dataclass
class PerformanceAlert:
    """性能告警数据结构"""
    alert_id: str
    level: AlertLevel
    metric_type: MetricType
    message: str
    threshold: Union[int, float]
    current_value: Union[int, float]
    timestamp: datetime = field(default_factory=datetime.now)
    resolved: bool = False
    metadata: Dict[str, Any] = field(default_factory=dict)


@dataclass
class PerformanceReport:
    """性能报告数据结构"""
    report_id: str
    start_time: datetime
    end_time: datetime
    metrics: List[PerformanceMetric]
    alerts: List[PerformanceAlert]
    summary: Dict[str, Any]
    recommendations: List[str]


class PerformanceThreshold:
    """性能阈值配置"""
    
    def __init__(self):
        self.thresholds = {
            # 查询性能阈值
            "query_duration_warning": 1.0,  # 秒
            "query_duration_error": 5.0,
            "query_duration_critical": 10.0,
            "slow_query_count_warning": 10,
            "slow_query_count_error": 50,
            
            # 聚合性能阈值
            "aggregation_duration_warning": 5.0,
            "aggregation_duration_error": 30.0,
            "aggregation_duration_critical": 60.0,
            "aggregation_memory_warning": 1024 * 1024 * 100,  # 100MB
            "aggregation_memory_error": 1024 * 1024 * 500,    # 500MB
            
            # 分区性能阈值
            "partition_creation_warning": 10.0,
            "partition_creation_error": 30.0,
            "partition_maintenance_warning": 60.0,
            "partition_maintenance_error": 300.0,
            
            # 批量操作阈值
            "batch_throughput_warning": 1000,  # 记录/秒
            "batch_throughput_error": 500,
            "batch_error_rate_warning": 0.01,  # 1%
            "batch_error_rate_error": 0.05,    # 5%
            
            # 缓存性能阈值
            "cache_hit_rate_warning": 0.8,     # 80%
            "cache_hit_rate_error": 0.6,       # 60%
            "cache_response_time_warning": 0.1, # 100ms
            "cache_response_time_error": 0.5,   # 500ms
            
            # 数据库连接阈值
            "db_connection_count_warning": 80,  # 连接数
            "db_connection_count_error": 95,
            "db_response_time_warning": 0.5,
            "db_response_time_error": 2.0,
            
            # 系统资源阈值
            "memory_usage_warning": 0.8,       # 80%
            "memory_usage_error": 0.9,         # 90%
            "cpu_usage_warning": 0.8,
            "cpu_usage_error": 0.9,
        }
    
    def get_threshold(self, metric_name: str, level: AlertLevel) -> Optional[float]:
        """获取指定指标和级别的阈值"""
        threshold_key = f"{metric_name}_{level.value}"
        return self.thresholds.get(threshold_key)
    
    def update_threshold(self, metric_name: str, level: AlertLevel, value: float):
        """更新阈值"""
        threshold_key = f"{metric_name}_{level.value}"
        self.thresholds[threshold_key] = value


class MetricCollector:
    """指标收集器"""
    
    def __init__(self, max_metrics: int = 10000):
        self.max_metrics = max_metrics
        self.metrics: deque = deque(maxlen=max_metrics)
        self.metric_index: Dict[str, List[PerformanceMetric]] = defaultdict(list)
        self._lock = asyncio.Lock()
    
    async def collect_metric(self, metric: PerformanceMetric):
        """收集性能指标"""
        async with self._lock:
            self.metrics.append(metric)
            
            # 按类型索引
            type_key = metric.metric_type.value
            self.metric_index[type_key].append(metric)
            
            # 限制索引大小
            if len(self.metric_index[type_key]) > self.max_metrics // 10:
                self.metric_index[type_key] = self.metric_index[type_key][-self.max_metrics // 10:]
    
    async def get_metrics(
        self,
        metric_type: Optional[MetricType] = None,
        start_time: Optional[datetime] = None,
        end_time: Optional[datetime] = None,
        limit: Optional[int] = None
    ) -> List[PerformanceMetric]:
        """获取性能指标"""
        async with self._lock:
            metrics = list(self.metrics)
            
            # 按类型过滤
            if metric_type:
                metrics = [m for m in metrics if m.metric_type == metric_type]
            
            # 按时间过滤
            if start_time:
                metrics = [m for m in metrics if m.timestamp >= start_time]
            if end_time:
                metrics = [m for m in metrics if m.timestamp <= end_time]
            
            # 限制数量
            if limit:
                metrics = metrics[-limit:]
            
            return metrics
    
    async def get_metric_statistics(
        self,
        metric_name: str,
        metric_type: Optional[MetricType] = None,
        start_time: Optional[datetime] = None,
        end_time: Optional[datetime] = None
    ) -> Dict[str, float]:
        """获取指标统计信息"""
        metrics = await self.get_metrics(metric_type, start_time, end_time)
        values = [m.value for m in metrics if m.name == metric_name]
        
        if not values:
            return {}
        
        return {
            "count": len(values),
            "min": min(values),
            "max": max(values),
            "mean": statistics.mean(values),
            "median": statistics.median(values),
            "std_dev": statistics.stdev(values) if len(values) > 1 else 0.0,
            "p95": statistics.quantiles(values, n=20)[18] if len(values) >= 20 else max(values),
            "p99": statistics.quantiles(values, n=100)[98] if len(values) >= 100 else max(values),
        }


class AlertManager:
    """告警管理器"""
    
    def __init__(self, max_alerts: int = 1000):
        self.max_alerts = max_alerts
        self.alerts: deque = deque(maxlen=max_alerts)
        self.active_alerts: Dict[str, PerformanceAlert] = {}
        self.thresholds = PerformanceThreshold()
        self._lock = asyncio.Lock()
    
    async def check_thresholds(self, metric: PerformanceMetric) -> Optional[PerformanceAlert]:
        """检查指标是否超过阈值"""
        # 检查各级别阈值
        for level in [AlertLevel.CRITICAL, AlertLevel.ERROR, AlertLevel.WARNING]:
            threshold = self.thresholds.get_threshold(metric.name, level)
            if threshold is None:
                continue
            
            # 根据指标类型判断是否超过阈值
            exceeded = False
            if metric.name.endswith(("_rate", "_usage")):
                # 比率类指标：低于阈值触发告警
                exceeded = metric.value < threshold
            else:
                # 其他指标：高于阈值触发告警
                exceeded = metric.value > threshold
            
            if exceeded:
                alert_id = f"{metric.metric_type.value}_{metric.name}_{level.value}"
                
                # 检查是否已有相同告警
                if alert_id in self.active_alerts:
                    # 更新现有告警
                    alert = self.active_alerts[alert_id]
                    alert.current_value = metric.value
                    alert.timestamp = datetime.now()
                    return alert
                
                # 创建新告警
                alert = PerformanceAlert(
                    alert_id=alert_id,
                    level=level,
                    metric_type=metric.metric_type,
                    message=f"{metric.name} {level.value}: {metric.value} {metric.unit} (threshold: {threshold})",
                    threshold=threshold,
                    current_value=metric.value,
                    metadata=metric.metadata
                )
                
                await self.add_alert(alert)
                return alert
        
        return None
    
    async def add_alert(self, alert: PerformanceAlert):
        """添加告警"""
        async with self._lock:
            self.alerts.append(alert)
            if not alert.resolved:
                self.active_alerts[alert.alert_id] = alert
    
    async def resolve_alert(self, alert_id: str):
        """解决告警"""
        async with self._lock:
            if alert_id in self.active_alerts:
                alert = self.active_alerts[alert_id]
                alert.resolved = True
                del self.active_alerts[alert_id]
    
    async def get_active_alerts(self, level: Optional[AlertLevel] = None) -> List[PerformanceAlert]:
        """获取活跃告警"""
        async with self._lock:
            alerts = list(self.active_alerts.values())
            if level:
                alerts = [a for a in alerts if a.level == level]
            return sorted(alerts, key=lambda x: x.timestamp, reverse=True)
    
    async def get_alert_history(
        self,
        start_time: Optional[datetime] = None,
        end_time: Optional[datetime] = None,
        limit: Optional[int] = None
    ) -> List[PerformanceAlert]:
        """获取告警历史"""
        async with self._lock:
            alerts = list(self.alerts)
            
            if start_time:
                alerts = [a for a in alerts if a.timestamp >= start_time]
            if end_time:
                alerts = [a for a in alerts if a.timestamp <= end_time]
            
            if limit:
                alerts = alerts[-limit:]
            
            return sorted(alerts, key=lambda x: x.timestamp, reverse=True)


class PerformanceMonitor:
    """性能监控集成接口"""
    
    def __init__(self):
        self.collector = MetricCollector()
        self.alert_manager = AlertManager()
        self.monitoring_enabled = True
        self.auto_alert_enabled = True
        self._monitoring_task: Optional[asyncio.Task] = None
        
        # 组件引用
        self._query_optimizer = None
        self._aggregation_optimizer = None
        self._partition_manager = None
        self._batch_optimizer = None
    
    async def start_monitoring(self):
        """启动性能监控"""
        if self._monitoring_task is None or self._monitoring_task.done():
            self._monitoring_task = asyncio.create_task(self._monitoring_loop())
            logger.info("性能监控已启动")
    
    async def stop_monitoring(self):
        """停止性能监控"""
        if self._monitoring_task and not self._monitoring_task.done():
            self._monitoring_task.cancel()
            try:
                await self._monitoring_task
            except asyncio.CancelledError:
                pass
            logger.info("性能监控已停止")
    
    async def _monitoring_loop(self):
        """监控循环"""
        while self.monitoring_enabled:
            try:
                # 收集系统指标
                await self._collect_system_metrics()
                
                # 收集数据库指标
                await self._collect_database_metrics()
                
                # 收集缓存指标
                await self._collect_cache_metrics()
                
                # 等待下一次收集
                await asyncio.sleep(config.performance.monitoring_interval)
                
            except asyncio.CancelledError:
                break
            except Exception as e:
                logger.error(f"监控循环错误: {e}")
                await asyncio.sleep(5)
    
    async def _collect_system_metrics(self):
        """收集系统指标"""
        try:
            import psutil
            
            # CPU使用率
            cpu_percent = psutil.cpu_percent(interval=1)
            await self.record_metric(
                MetricType.SYSTEM,
                "cpu_usage",
                cpu_percent / 100.0,
                "ratio"
            )
            
            # 内存使用率
            memory = psutil.virtual_memory()
            await self.record_metric(
                MetricType.SYSTEM,
                "memory_usage",
                memory.percent / 100.0,
                "ratio"
            )
            
            # 磁盘使用率
            disk = psutil.disk_usage('/')
            await self.record_metric(
                MetricType.SYSTEM,
                "disk_usage",
                disk.percent / 100.0,
                "ratio"
            )
            
        except ImportError:
            # psutil未安装，跳过系统指标收集
            pass
        except Exception as e:
            logger.error(f"收集系统指标失败: {e}")
    
    async def _collect_database_metrics(self):
        """收集数据库指标"""
        try:
            # 连接池状态
            pool = db_manager.get_pool()
            if pool:
                await self.record_metric(
                    MetricType.DATABASE,
                    "connection_count",
                    pool.size,
                    "count"
                )
                
                # 测试数据库响应时间
                start_time = time.time()
                async with db_manager.get_session() as session:
                    await session.execute("SELECT 1")
                response_time = time.time() - start_time
                
                await self.record_metric(
                    MetricType.DATABASE,
                    "response_time",
                    response_time,
                    "seconds"
                )
                
        except Exception as e:
            logger.error(f"收集数据库指标失败: {e}")
    
    async def _collect_cache_metrics(self):
        """收集缓存指标"""
        try:
            cache = cache_manager.get_cache()
            if cache:
                # 测试缓存响应时间
                start_time = time.time()
                await cache.ping()
                response_time = time.time() - start_time
                
                await self.record_metric(
                    MetricType.CACHE,
                    "response_time",
                    response_time,
                    "seconds"
                )
                
                # 获取缓存统计信息（如果支持）
                try:
                    info = await cache.info()
                    if 'keyspace_hits' in info and 'keyspace_misses' in info:
                        hits = int(info['keyspace_hits'])
                        misses = int(info['keyspace_misses'])
                        total = hits + misses
                        hit_rate = hits / total if total > 0 else 0
                        
                        await self.record_metric(
                            MetricType.CACHE,
                            "hit_rate",
                            hit_rate,
                            "ratio"
                        )
                except:
                    pass
                
        except Exception as e:
            logger.error(f"收集缓存指标失败: {e}")
    
    async def record_metric(
        self,
        metric_type: MetricType,
        name: str,
        value: Union[int, float],
        unit: str,
        tags: Optional[Dict[str, str]] = None,
        metadata: Optional[Dict[str, Any]] = None
    ):
        """记录性能指标"""
        if not self.monitoring_enabled:
            return
        
        metric = PerformanceMetric(
            metric_type=metric_type,
            name=name,
            value=value,
            unit=unit,
            tags=tags or {},
            metadata=metadata or {}
        )
        
        await self.collector.collect_metric(metric)
        
        # 自动告警检查
        if self.auto_alert_enabled:
            alert = await self.alert_manager.check_thresholds(metric)
            if alert:
                logger.warning(f"性能告警: {alert.message}")
    
    async def get_performance_summary(
        self,
        start_time: Optional[datetime] = None,
        end_time: Optional[datetime] = None
    ) -> Dict[str, Any]:
        """获取性能摘要"""
        if start_time is None:
            start_time = datetime.now() - timedelta(hours=1)
        if end_time is None:
            end_time = datetime.now()
        
        summary = {
            "period": {
                "start": start_time.isoformat(),
                "end": end_time.isoformat()
            },
            "metrics": {},
            "alerts": {
                "active": len(await self.alert_manager.get_active_alerts()),
                "total": len(await self.alert_manager.get_alert_history(start_time, end_time))
            }
        }
        
        # 按类型统计指标
        for metric_type in MetricType:
            metrics = await self.collector.get_metrics(metric_type, start_time, end_time)
            summary["metrics"][metric_type.value] = {
                "count": len(metrics),
                "latest": metrics[-1].timestamp.isoformat() if metrics else None
            }
        
        return summary
    
    async def generate_performance_report(
        self,
        start_time: Optional[datetime] = None,
        end_time: Optional[datetime] = None
    ) -> PerformanceReport:
        """生成性能报告"""
        if start_time is None:
            start_time = datetime.now() - timedelta(hours=24)
        if end_time is None:
            end_time = datetime.now()
        
        # 收集指标和告警
        metrics = await self.collector.get_metrics(None, start_time, end_time)
        alerts = await self.alert_manager.get_alert_history(start_time, end_time)
        
        # 生成摘要
        summary = await self.get_performance_summary(start_time, end_time)
        
        # 生成建议
        recommendations = await self._generate_recommendations(metrics, alerts)
        
        report = PerformanceReport(
            report_id=f"perf_report_{int(time.time())}",
            start_time=start_time,
            end_time=end_time,
            metrics=metrics,
            alerts=alerts,
            summary=summary,
            recommendations=recommendations
        )
        
        return report
    
    async def _generate_recommendations(
        self,
        metrics: List[PerformanceMetric],
        alerts: List[PerformanceAlert]
    ) -> List[str]:
        """生成性能优化建议"""
        recommendations = []
        
        # 分析告警模式
        alert_counts = defaultdict(int)
        for alert in alerts:
            alert_counts[alert.metric_type] += 1
        
        # 基于告警生成建议
        if alert_counts[MetricType.QUERY] > 10:
            recommendations.append("考虑优化查询性能：添加索引、重写慢查询、使用查询缓存")
        
        if alert_counts[MetricType.CACHE] > 5:
            recommendations.append("考虑优化缓存策略：增加缓存容量、调整过期时间、优化缓存键设计")
        
        if alert_counts[MetricType.DATABASE] > 5:
            recommendations.append("考虑优化数据库配置：调整连接池大小、优化数据库参数")
        
        if alert_counts[MetricType.BATCH] > 5:
            recommendations.append("考虑优化批量操作：调整批次大小、使用并行处理、优化事务策略")
        
        # 分析系统资源使用
        cpu_metrics = [m for m in metrics if m.name == "cpu_usage"]
        if cpu_metrics:
            avg_cpu = statistics.mean([m.value for m in cpu_metrics])
            if avg_cpu > 0.8:
                recommendations.append("CPU使用率过高，考虑优化算法复杂度或增加计算资源")
        
        memory_metrics = [m for m in metrics if m.name == "memory_usage"]
        if memory_metrics:
            avg_memory = statistics.mean([m.value for m in memory_metrics])
            if avg_memory > 0.8:
                recommendations.append("内存使用率过高，考虑优化内存使用或增加内存容量")
        
        return recommendations
    
    async def export_metrics(
        self,
        format_type: str = "json",
        start_time: Optional[datetime] = None,
        end_time: Optional[datetime] = None
    ) -> str:
        """导出性能指标"""
        metrics = await self.collector.get_metrics(None, start_time, end_time)
        
        if format_type.lower() == "json":
            data = []
            for metric in metrics:
                data.append({
                    "type": metric.metric_type.value,
                    "name": metric.name,
                    "value": metric.value,
                    "unit": metric.unit,
                    "timestamp": metric.timestamp.isoformat(),
                    "tags": metric.tags,
                    "metadata": metric.metadata
                })
            return json.dumps(data, indent=2, ensure_ascii=False)
        
        elif format_type.lower() == "csv":
            import csv
            import io
            
            output = io.StringIO()
            writer = csv.writer(output)
            
            # 写入标题行
            writer.writerow(["timestamp", "type", "name", "value", "unit", "tags", "metadata"])
            
            # 写入数据行
            for metric in metrics:
                writer.writerow([
                    metric.timestamp.isoformat(),
                    metric.metric_type.value,
                    metric.name,
                    metric.value,
                    metric.unit,
                    json.dumps(metric.tags),
                    json.dumps(metric.metadata)
                ])
            
            return output.getvalue()
        
        else:
            raise ValueError(f"不支持的导出格式: {format_type}")
    
    async def health_check(self) -> Dict[str, Any]:
        """健康检查"""
        health = {
            "status": "healthy",
            "timestamp": datetime.now().isoformat(),
            "components": {}
        }
        
        try:
            # 检查监控状态
            health["components"]["monitor"] = {
                "status": "healthy" if self.monitoring_enabled else "disabled",
                "metrics_count": len(self.collector.metrics),
                "active_alerts": len(self.alert_manager.active_alerts)
            }
            
            # 检查数据库连接
            try:
                async with db_manager.get_session() as session:
                    await session.execute("SELECT 1")
                health["components"]["database"] = {"status": "healthy"}
            except Exception as e:
                health["components"]["database"] = {"status": "unhealthy", "error": str(e)}
                health["status"] = "degraded"
            
            # 检查缓存连接
            try:
                cache = cache_manager.get_cache()
                await cache.ping()
                health["components"]["cache"] = {"status": "healthy"}
            except Exception as e:
                health["components"]["cache"] = {"status": "unhealthy", "error": str(e)}
                health["status"] = "degraded"
            
        except Exception as e:
            health["status"] = "unhealthy"
            health["error"] = str(e)
        
        return health


# 全局性能监控实例
performance_monitor = PerformanceMonitor()


# 便捷函数
async def record_metric(
    metric_type: MetricType,
    name: str,
    value: Union[int, float],
    unit: str,
    tags: Optional[Dict[str, str]] = None,
    metadata: Optional[Dict[str, Any]] = None
):
    """记录性能指标的便捷函数"""
    await performance_monitor.record_metric(metric_type, name, value, unit, tags, metadata)


async def get_performance_summary(
    start_time: Optional[datetime] = None,
    end_time: Optional[datetime] = None
) -> Dict[str, Any]:
    """获取性能摘要的便捷函数"""
    return await performance_monitor.get_performance_summary(start_time, end_time)


async def generate_performance_report(
    start_time: Optional[datetime] = None,
    end_time: Optional[datetime] = None
) -> PerformanceReport:
    """生成性能报告的便捷函数"""
    return await performance_monitor.generate_performance_report(start_time, end_time)


async def start_monitoring():
    """启动性能监控的便捷函数"""
    await performance_monitor.start_monitoring()


async def stop_monitoring():
    """停止性能监控的便捷函数"""
    await performance_monitor.stop_monitoring()